
package org.googlecode.viewt.core.contant;

import java.io.FileInputStream;

import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.ValidationException;
import org.googlecode.viewt.core.ReConfigurableFileCfgRepository;
import org.googlecode.viewt.core.SpringContextHelper;
import org.googlecode.viewt.core.contant.types.ConstDataDef;
import org.googlecode.viewt.core.contant.types.ConstDatas;
import org.googlecode.viewt.core.exception.ContextInitException;
import org.googlecode.viewt.core.exception.ResourceFailException;
import org.googlecode.viewt.core.exception.ResourceNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;


/**
 * @TODO 
 * @author Administrator
 *
 */
public class ConstantDataCfgRepository extends ReConfigurableFileCfgRepository {
	public static final String BEAN_NAME = "constantDataCfgRepository";
	private static ConstantDataCfgRepository instance = null;

	private Map constantMap = Collections.synchronizedMap(new HashMap());

	private Map fileMap = Collections.synchronizedMap(new HashMap());

	private static String lockObj = "LOCK";

	public Map getConstantMap() {
		return this.constantMap;
	}

	public Map getFileMap() {
		return this.fileMap;
	}

	/* (non-Javadoc)
	 * @see org.googlecode.viewt.base.IReConfigurableResources#reloadResource(java.lang.String)
	 */
	public Object reloadResource(String resourceUrl)
			throws ResourceNotFoundException, ResourceFailException {
		this.logger.debug("Loading constant data config from file:"
				+ resourceUrl);

		ConstDatas constDatas = null;
		try {
			Reader in = new InputStreamReader(new FileInputStream(resourceUrl));
			constDatas = ConstDatas.unmarshal(in);

			ConstDataDef[] dataDefs = constDatas.getConstDataDef();
			for (int i = 0; i < dataDefs.length; ++i) {
				ConstDataDef def = dataDefs[i];
				this.constantMap.put(def.getAlias(), def);
				this.fileMap.put(def.getAlias(), resourceUrl);
			}
		} catch (FileNotFoundException fnfEx) {
			this.logger.error("Constant config file:" + resourceUrl
					+ " not found, check your setting");
			throw new ResourceNotFoundException("Resource file:" + resourceUrl
					+ " not found", fnfEx);
		} catch (MarshalException marshalEx) {
			this.logger.error("Unmarshal constant config file:" + resourceUrl
					+ " fail", marshalEx);
			throw new ResourceFailException("Unmarshal constant config file:"
					+ resourceUrl + " fail", marshalEx);
		} catch (ValidationException validateEx) {
			this.logger.error("Validate constant config file:" + resourceUrl
					+ " fail", validateEx);
			throw new ResourceFailException("Validate constant config file:"
					+ resourceUrl + " fail", validateEx);
		}

		return constDatas;
	}

	/**
	 * @param name
	 * @return
	 * @throws ResourceNotFoundException
	 * @throws ResourceFailException
	 */
	public static ConstDataDef getConstConfig(String name)
			throws ResourceNotFoundException, ResourceFailException {
		Logger logger = LoggerFactory.getLogger(ConstantDataCfgRepository.class);
		if (logger.isDebugEnabled())
			logger.debug("Get config of constant:" + name);
		ConstantDataCfgRepository repository = getInstance();

		String resourceFile = (String) repository.getFileMap().get(name);
		if (resourceFile == null) {
			if (logger.isDebugEnabled())
				logger
						.debug("constant:" + name
								+ " not found, try to load all");
			repository.loadAll();
			resourceFile = (String) repository.getFileMap().get(name);
			if (logger.isDebugEnabled()) {
				logger.debug("load all done, file name for constant:"
						+ resourceFile);
			}
		}
		if (resourceFile == null) {
			return null;
		}

		repository.getResource(resourceFile);
		return ((ConstDataDef) repository.getConstantMap().get(name));
	}

	/**
	 * @return
	 * @throws ResourceFailException
	 */
	public static ConstantDataCfgRepository getInstance()
			throws ResourceFailException {
		synchronized (lockObj) {
			if (null == instance) {
				Logger logger = LoggerFactory.getLogger(ConstantDataCfgRepository.class);
				try {
					ApplicationContext context = SpringContextHelper
							.getContext();
					instance = (ConstantDataCfgRepository) context
							.getBean("constantDataCfgRepository");
				} catch (ContextInitException contextEx) {
					logger.error("Initialize spring context fail", contextEx);
					throw new ResourceFailException(
							"Initialize spring context fail", contextEx);
				} catch (BeansException beanEx) {
					logger.error("Create bean fail", beanEx);
					throw new ResourceFailException("Create bean fail", beanEx);
				}
			}
		}

		return instance;
	}
}